#include <cfg/os.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>

#include <dev/board.h>

#include <sys/heap.h>
#include <sys/thread.h>
#include <sys/timer.h>
#include <sys/socket.h>
#include <sys/confnet.h>
#include <sys/version.h>

#include <dev/debug.h>
#include <arpa/inet.h>
#include <dev/nicrtl.h>
#include <dev/uartavr.h>

#include <net/route.h>
#include <netinet/in.h>
#include <netdb.h>

#include <pro/dhcp.h>
#include <net/errno.h>
#include <dev/atcan.h>

#include <netinet/if_ether.h> 
#include <net/ether.h>

#include <dev/can_dev.h>
#include <dev/uartavr.h>

#ifdef NUTDEBUG
#include <sys/osdebug.h>
#include <net/netdebug.h>
#endif

// Only need data[8] for the program to work, but we
// left some more room for "expanding purposes".
static char data[128] = "Test-row";

CANFRAME canFrame; // <-- new CAN frame
CANINFO *canInfoPtr;

uint32_t dest_addr; // <-- for the destination address (UDP)

UDPSOCKET *socket; // <-- socket for the data (UDP)

extern NUTDEVICE devEth0;   //<----- Won't find ethernet device without this



// Can-thread
THREAD(canThread, arg){

	// configuring the CAN bus
   NutRegisterDevice(&devAtCan, 0, 0);
   canInfoPtr = (CANINFO *) devAtCan.dev_dcb;

   // Re-configure receive message objects
   AtCanEnableRx(14, // 14 CAN objects as RX buffer, 0 remaining as TX buffer
   				 1, // Acceptance code 1 (0 = accept all IDs)
				 1, // Flag if acceptance code is extended (0 = standard, 1 = extended)
				 0, // Acceptance code's remote tag (0 or 1)
				 0, // Acceptance mask
				 0, // 0 to receive extended and standard frames, 1 if message ID type must match acceptance code flag
				 0  // 0 to receive remote and standard frames, 1 if remote tag must match acceptance code's remote tag
				 ); 

   // Set CAN bit rate minimun length of cable, needs to be the same frequency on both ends.
   CAN_SetSpeed(&devAtCan, CAN_SPEED_800K);


   printf("Starting CAN RX/TX loop...\n");
   while(1)
   {
		// RX -- RECEIVE
			
		CAN_TryRxFrame(&devAtCan, &canFrame); // <-- Try receiving a CAN frame.
      	
		printf("canFrame.len = %d\n", canFrame.len); // <-- Print out the CAN frame lenght.
	
	    for (int j = 0; j < canFrame.len; j++) // <-- for loop for inputting the frame bytes into data[]
		{
			data[j] = canFrame.byte[j]; // <-- bytes to data
		}

		printf("CAN DATA: %s\n", data); // <-- Print out the received data.

		NutSleep(1000); // <-- Wait (sleep) for a second before trying to reveice a CAN frame again.
	  
   }


}


// UDP-thread
THREAD(udpThread, arg){

	dest_addr = inet_addr("172.29.132.121"); // <-- Setting the UDP destination address.

	while(1){
			socket = NutUdpCreateSocket(0); // <-- Creating a new UDP socket.
	       	NutUdpSendTo(socket, dest_addr, 4385, &data, strlen(data)); // <-- Sending UDP info, parameters: socketname, destination address, destination port, reference to the data that is sent, the lenght of the data.
			printf("UDP-Data: %s \n", data); // <-- Print out the sent data.

			NutSleep(10000); // <-- Wait (sleep) for 10 seconds before sending again.

	    	NutUdpDestroySocket(socket); // Destroying the socket.
	}
}



int main(void){
u_long baud = 115200;
    u_char mac[6] = { 0x00, 0x06, 0x98, 0x00, 0x00, 0x59 }; // <-- Setting the MAC address for the XNUT.
	

    // Opening stdout for the console
    NutRegisterDevice(&DEV_DEBUG, 0, 0); 
	freopen(DEV_DEBUG_NAME, "w", stdout);
    _ioctl(_fileno(stdout), UART_SETSPEED, &baud);

	// registering the ethernet
	NutRegisterDevice(&DEV_ETHER, 0x8300, 5 );

#ifdef NUTDEBUG
    NutTraceTcp(stdout, 1);
    NutTraceOs(stdout, 0);
    NutTraceHeap(stdout, 0);
    NutTracePPP(stdout, 0);
#endif

	// Loading old mac information
    NutNetLoadConfig(DEV_ETHER_NAME);
    memcpy(confnet.cdn_mac, mac, 6);
    NutNetSaveConfig();

    // Configuring the ethernet
    printf("Configuring eth0...");

	u_long ip_addr = inet_addr("172.29.130.85"); // <-- Setting the ip for the XNUT
    u_long ip_mask = inet_addr("255.255.255.0"); // <-- Setting the mask for the XNUT
	u_long ip_gate = inet_addr("172.29.130.1"); // <-- Setting the gateway for the XNUT

	printf( "IP: %s\n", inet_ntoa(ip_gate) ); 
	printf( "Trying a static IP:\n" );

    if(NutNetIfConfig2(DEV_ETHER_NAME, mac, ip_addr, ip_mask, ip_gate)) // <-- Try to get a static IP address.
	{
		printf( "Did not get a static IP!\n" );
	}
	else
	{
		printf("Got a static IP!\n");
	}
    
    puts("OK");

	//Print out the ethernet configuration information for the XNUT.
    printf( "IP: %s\n", inet_ntoa(confnet.cdn_ip_addr));
	printf( "Gateway: %s\n", inet_ntoa(confnet.cdn_gateway) ); 
	printf( "Mac: %2x.%2x.%2x.%2x.%2x.%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); 

	// Creating the threads.
    NutThreadCreate("can", canThread, 0, 192);
    NutThreadCreate("udp", udpThread, 0, 192);

	while (1)
	{
		 NutSleep(125); // <-- Wait (sleep) for 125 milliseconds.
	}
	return 0;
}